﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Timers;

namespace Quick.Common.Monitor
{
    /// <summary>
    /// 数据监控
    /// </summary>
    public  class Qmonitor
    {
        private static Dictionary<string, long> currentItems = new Dictionary<string, long>();
        private static Dictionary<string, MonitorItem> items = new Dictionary<string, MonitorItem>();
        private static Dictionary<string, MonitorItem> jvmItems = new Dictionary<string, MonitorItem>();
        private static double lastUpdate = 0.0;
        private static object lockObjCurrent = new object();
        private static object lockObjItems = new object();
        private static bool m_bLock = false;
        private static Timer timer = new Timer();

        public Qmonitor()
        {
            timer.Interval = 2000.0;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
            timer.Enabled = true;
        }

        public  Dictionary<string, long> GetValues()
        {
            lock (lockObjCurrent)
            {
                return currentItems;
            }
        }

        private string MakeName(string name)
        {
            return name.Replace(" ", "_");
        }

        /// <summary>
        /// 记录次数
        /// </summary>
        public  void RecordMany(string name, long count, long time)
        {
            lock (lockObjItems)
            {
                MonitorItem item;
                if (items.ContainsKey(name))
                {
                    item = items[name];
                }
                else
                {
                    item = new MonitorItem();
                    items.Add(name, item);
                }
                item.Add(count, time);
            }
        }

        /// <summary>
        /// 记录一次
        /// </summary>
        public  void RecordOne(string name)
        {
            RecordMany(name, 1L, 0L);
        }

        /// <summary>
        /// 记录一次
        /// </summary>
        public  void RecordOne(string name, long time)
        {
            RecordMany(name, 1L, time);
        }

        private  void Run()
        {
            try
            {
                DateTime now = DateTime.Now;
                DateTime time2 = Convert.ToDateTime("1970-01-01 00:00:00");
                TimeSpan span = (TimeSpan) (now - time2);
                double totalMilliseconds = span.TotalMilliseconds;
                if (((totalMilliseconds - lastUpdate) >= 50000.0) && (now.Second <= 10))
                {
                    lastUpdate = totalMilliseconds;
                    Dictionary<string, long> dictionary = new Dictionary<string, long>();
                    lock (lockObjItems)
                    {
                        dictionary.Add("Thread_Count", (long) Process.GetCurrentProcess().Threads.Count);
                        foreach (string str in items.Keys)
                        {
                            MonitorItem item = items[str].DumpAndClearItem();
                            long count = item.count;
                            long time = item.time;
                            dictionary.Add(MakeName(str + "_Count"), count);
                            if (count > 0L)
                            {
                                dictionary.Add(MakeName(str + "_Time"), time/count);
                            }
                            else
                            {
                                dictionary.Add(MakeName(str + "_Time"), 0L);
                            }
                        }
                    }
                    lock (lockObjCurrent)
                    {
                        currentItems = dictionary;
                    }
                }
            }
            catch
            {
            }
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (!m_bLock)
            {
                m_bLock = true;
                try
                {
                    Run();
                }
                catch
                {
                }
                finally
                {
                    m_bLock = false;
                }
            }
        }

        private class MonitorItem
        {
            public long count;
            private static bool m_bAddLock;
            private static bool m_bDumpAndClearLock;
            public long time;

            public void Add(long count, long time)
            {
                if (!m_bAddLock)
                {
                    m_bAddLock = true;
                    try
                    {
                        this.count += count;
                        this.time += time;
                    }
                    catch
                    {
                    }
                    finally
                    {
                        m_bAddLock = false;
                    }
                }
            }

            public Qmonitor.MonitorItem DumpAndClearItem()
            {
                if (!m_bDumpAndClearLock)
                {
                    m_bDumpAndClearLock = true;
                    try
                    {
                        Qmonitor.MonitorItem item = new Qmonitor.MonitorItem
                        {
                            count = this.count,
                            time = this.time
                        };
                        this.count = 0L;
                        this.time = 0L;
                        return item;
                    }
                    catch
                    {
                    }
                    finally
                    {
                        m_bDumpAndClearLock = false;
                    }
                }
                return null;
            }
        }
    }
}
